import type { Block, Board, Cell, Direction } from '../types'

const ROWS = 20
const COLS = 10

const shapes: Cell[][][] = [
  [[1, 1, 1, 1]],
  [[1, 1], [1, 1]],
  [[0, 1, 0], [1, 1, 1]],
  [[1, 1, 0], [0, 1, 1]],
  [[0, 1, 1], [1, 1, 0]],
  [[1, 0, 0], [1, 1, 1]],
  [[0, 0, 1], [1, 1, 1]],
]

function createEmptyBoard(): Board {
  return Array.from({ length: ROWS }, () => Array(COLS).fill(0))
}

function rotate(shape: Cell[][]): Cell[][] {
  return shape[0].map((_, i) => shape.map(row => row[i]).reverse())
}

function canPlace(block: Block, board: Board): boolean {
  return block.shape.every((row, y) =>
    row.every((cell, x) => {
      if (!cell)
        return true
      const newY = block.position.y + y
      const newX = block.position.x + x
      return (
        newY >= 0
        && newY < board.length
        && newX >= 0
        && newX < board[0].length
        && board[newY][newX] === 0
      )
    }),
  )
}

function generateBlock(): Block {
  const shape = shapes[Math.floor(Math.random() * shapes.length)]
  return {
    shape,
    position: { x: 3, y: 0 },
  }
}

function clearLines(board: Board): number {
  const newBoard = board.filter(row => row.includes(0))
  const cleared = board.length - newBoard.length
  while (newBoard.length < board.length) {
    newBoard.unshift(Array(COLS).fill(0))
  }
  for (let y = 0; y < board.length; y++) {
    board[y] = newBoard[y]
  }
  return cleared
}

export function useTetris(onGameOver: () => void) {
  const board = ref<Board>(createEmptyBoard())
  const score = ref(0)
  const currentBlock = ref<Block>(generateBlock())

  function placeBlock() {
    currentBlock.value.shape.forEach((row, y) =>
      row.forEach((cell, x) => {
        if (cell) {
          const px = currentBlock.value.position.x + x
          const py = currentBlock.value.position.y + y
          if (py >= 0 && py < board.value.length && px >= 0 && px < board.value[0].length) {
            board.value[py][px] = 1
          }
        }
      }),
    )
  }

  function moveBlock(direction: Direction) {
    const newBlock: Block = {
      shape: currentBlock.value.shape,
      position: { ...currentBlock.value.position },
    }

    if (direction === 'left')
      newBlock.position.x--
    else if (direction === 'right')
      newBlock.position.x++
    else if (direction === 'down')
      newBlock.position.y++
    else if (direction === 'rotate')
      newBlock.shape = rotate(newBlock.shape)

    if (canPlace(newBlock, board.value)) {
      currentBlock.value = newBlock
    }
  }

  function tick() {
    const tempBlock: Block = {
      shape: currentBlock.value.shape,
      position: { x: currentBlock.value.position.x, y: currentBlock.value.position.y + 1 },
    }

    if (canPlace(tempBlock, board.value)) {
      currentBlock.value = tempBlock
    }
    else {
      placeBlock()
      const linesCleared = clearLines(board.value)
      if (linesCleared > 0) {
        score.value += linesCleared * 100
      }
      currentBlock.value = generateBlock()
      if (!canPlace(currentBlock.value, board.value)) {
        onGameOver()
      }
    }
  }

  function getBoardWithBlock(): Board {
    const tempBoard = board.value.map(row => [...row])
    currentBlock.value.shape.forEach((row, y) =>
      row.forEach((cell, x) => {
        if (cell) {
          const px = currentBlock.value.position.x + x
          const py = currentBlock.value.position.y + y
          if (py >= 0 && py < tempBoard.length && px >= 0 && px < tempBoard[0].length) {
            tempBoard[py][px] = 1
          }
        }
      }),
    )
    return tempBoard
  }

  function reset() {
    board.value = createEmptyBoard()
    score.value = 0
    currentBlock.value = generateBlock()
  }

  return {
    board,
    score,
    moveBlock,
    tick,
    getBoardWithBlock,
    reset,
  }
}
